package com.ftqh.tutorial.security.oauth2.controller;

import com.ftqh.tutorial.security.oauth2.provider.client.OAuth2ClientDetails;
import com.ftqh.tutorial.security.oauth2.provider.client.OAuth2ClientDetailsRepository;
import com.ftqh.tutorial.security.oauth2.provider.client.OAuth2ClientDetailsService;
import com.ftqh.tutorial.security.oauth2.provider.client.enums.GrantScope;
import lombok.extern.java.Log;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.provider.ClientAlreadyExistsException;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.ArrayList;

@RestController
@RequestMapping("/clientDetails")
@PreAuthorize("hasRole('ROLE_ADMIN')")
@Log
public class OAuth2ClientDetailsController {

    private OAuth2ClientDetailsRepository oAuth2ClientDetailsRepository;

    private OAuth2ClientDetailsService clientDetailsService;

    OAuth2ClientDetailsController(OAuth2ClientDetailsRepository oAuth2ClientDetailsRepositor,
                                  OAuth2ClientDetailsService clientDetailsService){
        this.oAuth2ClientDetailsRepository = oAuth2ClientDetailsRepositor;
        this.clientDetailsService = clientDetailsService;
    }
    @GetMapping
    public ModelAndView findAll(@RequestParam(name = "edit", required = false) String editClientDetails, Pageable pageable) {
        ModelAndView model = new ModelAndView("clients/clientDetails");
        OAuth2ClientDetails oAuth2ClientDetails = OAuth2ClientDetails.builder().build();
        if (!StringUtils.isEmpty(editClientDetails)) {
            model.addObject("edit", true);
            oAuth2ClientDetails = findOne(editClientDetails);
        }
        model.addObject("clientDetails", oAuth2ClientDetails);
        model.addObject("clientDetailsList", oAuth2ClientDetailsRepository.findAll(pageable));
        model.addObject("grantScopes", GrantScope.values());
        model.addObject("resourceIds", new ArrayList<>());
        return model;
    }

    @GetMapping("/{clientId}")
    public OAuth2ClientDetails findOne(@PathVariable("clientId") String clientId) {
        return clientDetailsService.findOne(clientId)
                .orElseThrow(() -> new NoSuchClientException("No client found with id = " + clientId));
    }

    /*@PostMapping
    public ResponseEntity<Void> addOAuth2ClientDetails(@RequestBody OAuth2ClientDetails oAuth2ClientDetails, UriComponentsBuilder ucBuilder) {
        try {
            clientDetailsService.addOAuth2ClientDetails(oAuth2ClientDetails);
        }catch(ClientAlreadyExistsException e){
            log.warning("Client already exists: " + oAuth2ClientDetails.getClientId());
            return new ResponseEntity<>(HttpStatus.CONFLICT);
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(ucBuilder.path("/clientDetails/{id}").buildAndExpand(oAuth2ClientDetails.getClientId()).toUri());
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }*/

    @PostMapping
    public ResponseEntity<OAuth2ClientDetails> addOAuth2ClientDetails(@RequestBody OAuth2ClientDetails oAuth2ClientDetails, UriComponentsBuilder ucBuilder) {
        try {
            clientDetailsService.addOAuth2ClientDetails(oAuth2ClientDetails);
        }catch(ClientAlreadyExistsException e){
            log.warning("Client already exists: " + oAuth2ClientDetails.getClientId());
            return ResponseEntity.status(HttpStatus.CONFLICT).body(null);
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(ucBuilder.path("/clientDetails/{id}").buildAndExpand(oAuth2ClientDetails.getClientId()).toUri());
        return new ResponseEntity<>(oAuth2ClientDetails, headers, HttpStatus.CREATED);
    }

    @PutMapping("/{clientId}")
    public ResponseEntity<String> updateOAuth2ClientDetails(@PathVariable("clientId") String clientId,
                                                          @RequestBody OAuth2ClientDetails oAuth2ClientDetails,
                                                          UriComponentsBuilder ucBuilder){
        if(oAuth2ClientDetails.getClientId()!=null && clientId.equals(oAuth2ClientDetails.getClientId())){
            //new NoSuchClientException("Path ClientId("+clientId+") is different from the clientId("+oAuth2ClientDetails.getClientId()+") entity");
            log.warning("Path ClientId("+clientId+") is different from the clientId("+oAuth2ClientDetails.getClientId()+") entity");
            return new ResponseEntity<> (clientId, HttpStatus.NOT_FOUND);
        }
        oAuth2ClientDetails.setClientId(clientId);
        clientDetailsService.updateOAuth2ClientDetails(oAuth2ClientDetails);
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(ucBuilder.path("/clientDetails").buildAndExpand(oAuth2ClientDetails.getClientId()).toUri());
        return new ResponseEntity<>(headers, HttpStatus.RESET_CONTENT);
    }
    @DeleteMapping(path = "/{clientId}",
                    produces = {MediaType.TEXT_HTML_VALUE, MediaType.APPLICATION_XHTML_XML_VALUE}
    )
    public ResponseEntity delete(@PathVariable("clientId") String clientId, RedirectAttributes attributes) {
        try {
            clientDetailsService.removeClientDetails(clientId);
        } catch (NoSuchClientException e) {
            return new ResponseEntity("No client with requested id : " + clientId, HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity(clientId, HttpStatus.OK);
    }
}
